# 打猴子补丁
from gevent import monkey

monkey.patch_all()
# 导入协程池
from gevent.pool import Pool

from IPProxyPool.settings import PROXIES_SPIDERS,RUN_SPIDERS_INTERVAL
import importlib
from IPProxyPool.core.proxy_validate.httpbin_validator import check_proxy
from IPProxyPool.core.db.mongo_pool import MongoProxiesPool
from IPProxyPool.utils.log import logger

import schedule
import time


# 目标: 根据配置文件信息, 加载爬虫, 获取代理IP, 进行检验, 检验后写入到数据库中

# 在spiders目录下创建run_spider.py文件, 创建RunSpider类
# 提供一个运行爬虫的run方法
#     根据配置文件信息, 加载爬虫, 把爬虫对象放到列表中
#     遍历爬虫对象列表, 获取代理, 检测代理(代理IP检测模块), 写入数据库(数据库模块)
# 使用异步来执行每一个爬虫任务
# 每隔一定的时间, 执行一次爬取任务

class RunSpider():

    def __init__(self):
        self.mongo_pool = MongoProxiesPool()
        # 创建协程池对象
        self.coroutine_pool = Pool()

    def get_spider_from_settings(self):
        # 根据配置，获取爬虫信息
        for full_name in PROXIES_SPIDERS:
            # 'core.proxy_spider.proxy_spiders.YpieSpider',
            module_name, class_name = full_name.rsplit('.', maxsplit=1)
            # 根据模块名字导入模块
            module = importlib.import_module(module_name)
            # 根据类名获取类
            cls = getattr(module, class_name)
            # 创建爬虫对象
            spider = cls()
            yield spider

    def run(self):
        # 根据配置，获取爬虫信息
        spiders = self.get_spider_from_settings()
        # 执行爬虫方法，获取代理对象
        for spider in spiders:
            # 异步执行
            # self.__execute_one_spider_task(spider)
            self.coroutine_pool.apply_async(self.__execute_one_spider_task, args=(spider,))

        # 等待所有任务完成再退出
        self.coroutine_pool.join()

    def __execute_one_spider_task(self, spider):
        # 用于一个爬虫的爬虫任务
        # 处理异常
        try:
            # 遍历一个个代理
            for proxy in spider.get_proxies():
                # 获取一个个proxy字典拿去测试
                proxy = check_proxy(proxy)
                # 如果可用那么入库，speed不为-1 就表示可用
                if proxy.speed != -1:
                    self.mongo_pool.insert_one(proxy)
        except Exception as e:
            logger.exception(e)

    @classmethod
    def start(cls):
        # 创建类方法 此方法为自动运行爬虫使用
        # 一开始运行一次
        rs = RunSpider()
        rs.run()
        # 使用schedule每间隔多少时间运行一次
        schedule.every(RUN_SPIDERS_INTERVAL).hours.du(rs.run)
        while 1:
            schedule.run_pending()
            time.sleep(60)  # 每60秒检查一次是不是24小时到点了
        a


if __name__ == '__main__':
    # run = RunSpider()
    # run.run()

    # 测试schedule
    # def task():
    #     print('ablat')
    #
    #
    # schedule.every(7).seconds.do(task)
    # while 1:
    #     schedule.run_pending()
    #     time.sleep(1)

    # 类方法直接写
    RunSpider.start()
